home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / mush-7.1.1 / sort.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-05-02  |  7.9 KB  |  292 lines

  1. /* sort.c 3.0    (c) copyright 1986,1990 (Dan Heller) */
  2.  
  3. #include "mush.h"
  4. /* #define MYQSORT */
  5.  
  6. /* The size of this array should really be bounded by
  7.  * 2 spaces for each possible different sort criteria
  8.  * (one space for each key letter and one per for 'r'),
  9.  * but 16 leaves room to add to the current list.
  10.  */
  11. static char subsort[16];
  12.  
  13. static int depth, order, ignore_case;
  14. static jmp_buf sortbuf;
  15.  
  16. sort(argc, argv, list)
  17. register int argc;
  18. register char *argv[], list[];
  19. {
  20.     int msg_cmp();
  21.     SIGRET (*oldint)(), (*oldquit)();
  22.     int n, offset = -1, range = 0;
  23.     long curr_msg_off = msg[current_msg].m_offset;
  24.  
  25.     depth = 0, order = 1, ignore_case = FALSE;
  26.  
  27.     while (argc && *++argv) {
  28.     n = (argv[0][0] == '-' && argv[0][1] != 0);
  29.     while (argv[0][n]) {
  30.         if (depth > sizeof subsort - 2)
  31.         break;
  32.         switch(argv[0][n]) {
  33.         case '-': /* reverse order of next criteria (obsolete) */
  34.             argv[0][n] = 'r'; /* fix it and fall through */
  35.         case 'r': /* reverse order of next criteria */
  36.         case 'd': /* sort by date */
  37.         case 'a': /* sort by author (address) */
  38.         case 's': /* sort by subject (ignore Re:) */
  39.         case 'R': /* sort by subject including Re: */
  40.         case 'l': /* sort by length in bytes */
  41.         case 'S': /* sort by message status */
  42.             /* skip consecutive repeats of the same flag */
  43.             if (subsort[depth-1] != argv[0][n])
  44.             subsort[depth++] = argv[0][n];
  45.         when 'i': ignore_case = TRUE;
  46.         otherwise: return help(0, "sort", cmd_help);
  47.         }
  48.         n++;
  49.     }
  50.     }
  51.     if (depth == 0 || subsort[depth-1] == 'r')
  52.     subsort[depth++] = 'S'; /* status sort is the default */
  53.     subsort[depth] = 0;
  54.     depth = 0;    /* start at the beginning */
  55.     if (msg_cnt <= 1) {
  56.     print("Not enough messages to sort.\n");
  57.     return -1;
  58.     }
  59.     turnon(glob_flags, IGN_SIGS);
  60.     on_intr();
  61.  
  62.     if (list && ison(glob_flags, IS_PIPE)) {
  63.     for (n = 0; n < msg_cnt; n++)
  64.         if (msg_bit(list, n)) {
  65.         if (offset < 0)
  66.             offset = n;
  67.         range++;
  68.         } else if (offset >= 0)
  69.         break;
  70.     } else
  71.     offset = 0, range = msg_cnt;
  72.  
  73.     if (range < 2)
  74.     print("Range not broad enough to sort anything\n");
  75.     else {
  76.     Debug("Sorting %d messages starting at message %d\n", range, offset+1);
  77.  
  78.     if (setjmp(sortbuf) == 0)
  79.         qsort((char *)&msg[offset], range, sizeof (struct msg), msg_cmp);
  80.     else
  81.         print("WARNING: Sorting interrupted: unpredictable order.\n");
  82.     turnon(glob_flags, DO_UPDATE);
  83.     }
  84.     for (n = 0; n < msg_cnt; n++)
  85.     if (msg[n].m_offset == curr_msg_off)
  86.         break;
  87.     current_msg = n;
  88.     turnoff(glob_flags, IGN_SIGS);
  89.     off_intr();
  90.     /* Break pipes because message lists are invalid */
  91.     return 0 - in_pipe();
  92. }
  93.  
  94. #ifdef MYQSORT
  95. qsort(base, len, siz, compar)
  96. register struct msg *base;
  97. int (*compar)();
  98. {
  99.      register int i, swapping;
  100.      struct msg temp;
  101.  
  102.      do  {
  103.      swapping = 0;
  104.      for (i = 0; i < len-1; ++i) {
  105.          if (compar(base+i, base+i+1) > 0) {
  106.          temp = base[i];
  107.          base[i] = base[i+1];
  108.          base[i+1] = temp;
  109.          swapping = 1;
  110.          }
  111.      }
  112.      } while (swapping);
  113. }
  114. #endif /* MYSORT */
  115.  
  116. status_cmp(msg1, msg2)
  117. register struct msg *msg1, *msg2;
  118. {
  119.     if (msg1->m_flags == msg2->m_flags)
  120.     return msg_cmp(msg1, msg2);
  121.     if (ison(msg1->m_flags, DELETE) && isoff(msg2->m_flags, DELETE))
  122.     return order;
  123.     if (isoff(msg1->m_flags, DELETE) && ison(msg2->m_flags, DELETE))
  124.     return -order;
  125.     if (isoff(msg1->m_flags, OLD) && ison(msg2->m_flags, OLD))
  126.     return -order;
  127.     if (ison(msg1->m_flags, OLD) && isoff(msg2->m_flags, OLD))
  128.     return order;
  129.     if (ison(msg1->m_flags, UNREAD) && isoff(msg2->m_flags, UNREAD))
  130.     return -order;
  131.     if (isoff(msg1->m_flags, UNREAD) && ison(msg2->m_flags, UNREAD))
  132.     return order;
  133.     if (ison(msg1->m_flags,PRESERVE) && isoff(msg2->m_flags,PRESERVE))
  134.     return -order;
  135.     if (isoff(msg1->m_flags,PRESERVE) && ison(msg2->m_flags,PRESERVE))
  136.     return order;
  137.     if (ison(msg1->m_flags,REPLIED) && isoff(msg2->m_flags,REPLIED))
  138.     return -order;
  139.     if (isoff(msg1->m_flags,REPLIED) && ison(msg2->m_flags,REPLIED))
  140.     return order;
  141.     if (ison(msg1->m_flags,SAVED) && isoff(msg2->m_flags,SAVED))
  142.     return -order;
  143.     if (isoff(msg1->m_flags,SAVED) && ison(msg2->m_flags,SAVED))
  144.     return order;
  145.     if (ison(msg1->m_flags,PRINTED) && isoff(msg2->m_flags,PRINTED))
  146.     return -order;
  147.     if (isoff(msg1->m_flags,PRINTED) && ison(msg2->m_flags,PRINTED))
  148.     return order;
  149.     if (ison(msg1->m_flags,FORWARD) && isoff(msg2->m_flags,FORWARD))
  150.     return -order;
  151.     if (isoff(msg1->m_flags,FORWARD) && ison(msg2->m_flags,FORWARD))
  152.     return order;
  153.  
  154.     return order;
  155. }
  156.  
  157. author_cmp(msg1, msg2)
  158. register struct msg *msg1, *msg2;
  159. {
  160.     char buf1[HDRSIZ], buf2[HDRSIZ];
  161.     int retval;
  162.  
  163.     (void) reply_to(msg1 - msg, 0, buf1); /* "0" for "author only" */
  164.     (void) reply_to(msg2 - msg, 0, buf2);
  165.     Debug("author: msg %d: %s, msg %d: %s\n", msg1-msg, buf1, msg2-msg, buf2);
  166.     if (ignore_case)
  167.     retval = lcase_strncmp(buf1, buf2, -1) * order;
  168.     else
  169.     retval = strcmp(buf1, buf2) * order;
  170.     return retval ? retval : msg_cmp(msg1, msg2);
  171. }
  172.  
  173. /* compare messages according to size (length) */
  174. size_cmp(msg1, msg2)
  175. register struct msg *msg1, *msg2;
  176. {
  177.     int retval;
  178.  
  179.     Debug("sizes: (%d): %d, (%d): %d\"\n",
  180.     msg1-msg, msg1->m_size, msg2-msg, msg2->m_size);
  181.     if (retval = (msg1->m_size - msg2->m_size) * order) /* assign and test */
  182.     return retval;
  183.     return msg_cmp(msg1, msg2);
  184. }
  185.  
  186. /*
  187.  * Subject comparison ignoring Re:  subject_to() appends an Re: if there is
  188.  * any subject whatsoever.
  189.  */
  190. subject_cmp(msg1, msg2)
  191. register struct msg *msg1, *msg2;
  192. {
  193.     char buf1[HDRSIZ], buf2[HDRSIZ];
  194.     register char *p1, *p2;
  195.     int retval;
  196.  
  197.     p1 = subject_to(msg1 - msg, buf1);
  198.     p2 = subject_to(msg2 - msg, buf2);
  199.     if (p1) {
  200.     p1 += 4;
  201.     while (isspace(*p1))
  202.         p1++;
  203.     } else
  204.     p1 = buf1; /* subject_to() makes it an empty string */
  205.     if (p2) {
  206.     p2 += 4;
  207.     while (isspace(*p2))
  208.         p2++;
  209.     } else
  210.     p2 = buf2; /* subject_to() makes it an empty string */
  211.     Debug("subjects: (%d): \"%s\" (%d): \"%s\"\n", msg1-msg, p1, msg2-msg, p2);
  212.     if (ignore_case)
  213.     retval = lcase_strncmp(p1, p2, -1) * order;
  214.     else
  215.     retval = strcmp(p1, p2) * order;
  216.     return retval ? retval : msg_cmp(msg1, msg2);
  217. }
  218.  
  219. /*
  220.  * compare subject strings from two messages.
  221.  * If Re is appended, so be it -- if user wants to ignore Re: use 'R' flag.
  222.  */
  223. subj_with_re(msg1, msg2)
  224. register struct msg *msg1, *msg2;
  225. {
  226.     char buf1[HDRSIZ], buf2[HDRSIZ], *p;
  227.     int retval;
  228.  
  229.     if (!(p = header_field(msg1 - msg, "subject")))
  230.     p = "";
  231.     (void) strcpy(buf1, p);
  232.     if (!(p = header_field(msg2 - msg, "subject")))
  233.     p = "";
  234.     (void) strcpy(buf2, p);
  235.     Debug("subjects: (%d): \"%s\" (%d): \"%s\"\n",
  236.     msg1-msg, buf1, msg2-msg, buf2);
  237.     if (ignore_case)
  238.     retval = lcase_strncmp(buf1, buf2, -1) * order;
  239.     else
  240.     retval = strcmp(buf1, buf2) * order;
  241.     return retval ? retval : msg_cmp(msg1, msg2);
  242. }
  243.  
  244. date_cmp(msg1, msg2)
  245. register struct msg *msg1, *msg2;
  246. {
  247.     int retval;
  248.     long tm1, tm2;
  249.  
  250.     if (ison(glob_flags, DATE_RECV)) {
  251.     (void) sscanf(msg1->m_date_recv, "%ld", &tm1);
  252.     (void) sscanf(msg2->m_date_recv, "%ld", &tm2);
  253.     } else {
  254.     (void) sscanf(msg1->m_date_sent, "%ld", &tm1);
  255.     (void) sscanf(msg2->m_date_sent, "%ld", &tm2);
  256.     }
  257.     return tm1 < tm2 ? -order : (tm1 > tm2) ? order : msg_cmp(msg1, msg2);
  258. }
  259.  
  260. static
  261. msg_cmp(msg1, msg2)
  262. register struct msg *msg1, *msg2;
  263. {
  264.     int sv_order = order, sv_depth = depth, retval = 0;
  265.  
  266.     if (ison(glob_flags, WAS_INTR))
  267.     longjmp(sortbuf, 1);
  268.     if (msg1 < msg || msg2 < msg) {
  269.     wprint("sort botch trying to sort %d and %d using %s\n",
  270.         msg1-msg, msg2-msg, subsort);
  271.     return 0;
  272.     }
  273.  
  274.     if (subsort[depth] == 'r') {
  275.     order = -1;
  276.     depth++;
  277.     } else
  278.     order = 1;
  279.     switch(subsort[depth++]) {
  280.     case '\0': retval = 0;
  281.     when 'd': retval = date_cmp(msg1, msg2);
  282.     when 'a': retval = author_cmp(msg1, msg2);
  283.     when 's': retval = subject_cmp(msg1, msg2);
  284.     when 'R': retval = subj_with_re(msg1, msg2);
  285.     when 'l': retval = size_cmp(msg1, msg2); /* length compare */
  286.     otherwise: retval = status_cmp(msg1, msg2);
  287.     }
  288.     depth = sv_depth;
  289.     order = sv_order;
  290.     return retval;
  291. }
  292.